//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//     ____________  ____________   __       __
//    /+++++++++++/ /+++++++++++/  /+/      /+/
//    /+/                /+/       /+/      /+/
//    /+/______          /+/       /+/______/+/
//    /++++++++/         /+/       /++++++++++/
//    /+/                /+/       /+/      /+/
//    /+/__________      /+/       /+/      /+/
//    /+++++++++++/      /+/       /+/      /+/
//    __________________________________________
//                __________________
//            ____|Edited by Ethmods|____
//           |Code from SADX by XMakarusX| 
//
//                  Youtube Channel:
//       https://m.youtube.com/channel/UCqscbzXtZxyYdTeFWowXSRA
//
//                   Facebook Page:
//       http://www.facebook.com/Ethmods_2-112120047647743
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ENBSeries effect file
// visit http://enbdev.com for updates
// Copyright (c) 2007-2021 Boris Vorontsov
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



//+++++++++++++++++++++++++++++
//internal parameters, can be modified
//+++++++++++++++++++++++++++++

bool EPuddlesalltime <string UIName="Puddles_alltime";	> = {true};
float EPuddlesAmount <string UIName="Puddles_alltime: Amount";string UIWidget="Spinner";float UIMin=0.0;float UIMax=2.0;> = {0.65};
float EPuddlesSize <string UIName="Puddles_alltime: Size";string UIWidget="Spinner";float UIMin=0.0;float UIMax=0.1;> = {0.01};


//+++++++++++++++++++++++++++++
//external parameters, do not modify
//+++++++++++++++++++++++++++++
//keyboard controlled temporary variables (in some versions exists in the config file). Press and hold key 1,2,3...8 together with PageUp or PageDown to modify. By default all set to 1.0
float4	tempF1; //0,1,2,3
float4	tempF2; //5,6,7,8
float4	tempF3; //9,0
//x=Width, y=1/Width, z=ScreenScaleY, w=1/ScreenScaleY
float4	ScreenSize;
//x=generic timer in range 0..1, period of 16777216 ms (4.6 hours), w=frame time elapsed (in seconds)
float4	Timer;
//changes in range 0..1, 0 means that night time, 1 - day time
float	ENightDayFactor;
//changes 0 or 1. 0 means that exterior, 1 - interior
float	EInteriorFactor;
//.x - current weather index, .y - incoming weather index, .z - weather transition, .w - time of the day in 24 standart hours. Weather index is value from _weatherlist.ini, for example WEATHER002 means index==2, but index==0 means that weather not captured.
float4	WeatherAndTime;
//adaptation delta time for focusing
float	FadeFactor;
//fov in degrees
float	FieldOfView;
//time in 0..24 format
float	GameTime;
//sun direction in world space
float4	SunDirection; //.w - 1 when sun is set
//constants set in enbhelper.dll, can be anything captured from game
float4	CustomShaderConstants1[8];

//transposed transform matrix view*projection and inverse of it
float4	MatrixVP[4];
float4	MatrixInverseVP[4];
float4	MatrixVPRotation[4];
float4	MatrixInverseVPRotation[4];
float4	MatrixView[4];
float4	MatrixInverseView[4];
float4	CameraPosition;


float4x4	MatrixWVP;
float4x4	MatrixWVPInverse;
float4x4	MatrixWorld;
float4x4	MatrixProj;
float4	FogParam; //x - nearclip, y - farclip, z - fog start, w - fog end
float4	FogFarColor;


//textures
texture2D texEnv;
texture2D texOriginal;
texture2D texColor;
texture2D texDepth;
texture2D texNoise;
texture2D texNormal;
texture2D texPd < string ResourceName="enbpuddles.png"; >;
texture2D texRipples < string ResourceName="enbripples.png"; >;
texture2D texwrl < string ResourceName="enbnormal.png"; >;

sampler2D SamplerEnv = sampler_state
{
	Texture   = <texEnv>;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU  = Mirror;
	AddressV  = Mirror;
	SRGBTexture=FALSE;
	MaxMipLevel=0;
	MipMapLodBias=0;
};

sampler2D SamplerOriginal = sampler_state
{
	Texture   = <texOriginal>;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;//NONE;
	AddressU  = Clamp;
	AddressV  = Clamp;
	SRGBTexture=FALSE;
	MaxMipLevel=0;
	MipMapLodBias=0;
};

sampler2D SamplerWrl = sampler_state
{
	Texture = <texwrl>;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU = Wrap;
	AddressV = Wrap;
	AddressW = Wrap;
	SRGBTexture=TRUE;
	MaxMipLevel=1;
	MipMapLodBias=0;
};

sampler2D SamplerWrp = sampler_state
{
	Texture = <texRipples>;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU = Wrap;
	AddressV = Wrap;
	AddressW = Wrap;
	SRGBTexture=TRUE;
	MaxMipLevel=1;
	MipMapLodBias=0;
};

sampler2D SamplerNormal = sampler_state
{
	Texture   = <texNormal>;
	MinFilter = Anisotropic;
	MagFilter = Anisotropic;
	MipFilter = LINEAR;
	AddressU  = Wrap;
	AddressV  = Wrap;
	SRGBTexture=FALSE;
	MaxMipLevel=0;
	MipMapLodBias=0;
};

sampler2D SamplerColor = sampler_state
{
	Texture   = <texColor>;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = NONE;
	AddressU  = Clamp;
	AddressV  = Clamp;
	SRGBTexture=TRUE;
	MaxMipLevel=2;
	MipMapLodBias=0;
};

sampler2D SamplerDepth = sampler_state
{
	Texture   = <texDepth>;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU = Wrap;
	AddressV = Wrap;
	AddressW = Wrap;
	SRGBTexture=TRUE;
	MaxMipLevel=1;
	MipMapLodBias=0;
};

sampler2D SamplerNoise = sampler_state
{
	Texture   = <texNoise>;
	MinFilter = POINT;
	MagFilter = POINT;
	MipFilter = NONE;
	AddressU  = Wrap;
	AddressV  = Wrap;
	SRGBTexture=FALSE;
	MaxMipLevel=2;
	MipMapLodBias=0;
};

sampler2D SamplerPuddle = sampler_state
{
   Texture   = <texPd>;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU = Wrap;
	AddressV = Wrap;
	AddressW = Wrap;
	SRGBTexture=FALSE;
	MaxMipLevel=0;
	MipMapLodBias=0;
};

struct VS_OUTPUT_POST
{
	float4 vpos  : POSITION;
	float2 txcoord : TEXCOORD0;
};

struct VS_INPUT_POST
{
	float3 pos  : POSITION;
	float2 txcoord : TEXCOORD0;
};



//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
VS_OUTPUT_POST VS_PostProcess(VS_INPUT_POST IN)
{
	VS_OUTPUT_POST OUT;
	float4 pos=float4(IN.pos.x,IN.pos.y,IN.pos.z,1.0);
	OUT.vpos=pos;
	OUT.txcoord.xy=IN.txcoord.xy;
	return OUT;
}

float linearlizeDepth(float nonlinearDepth)
{
float2 dofProj = float2(0.0509804, 3098.0392);
float2 dofDist = float2(0.0, 0.0509804);
float4 depth = nonlinearDepth;
       depth.y = -dofProj.x + dofProj.y;
       depth.y = 1.0/depth.y;
       depth.z = depth.y * dofProj.y;
       depth.z = depth.z * -dofProj.x;
       depth.x = dofProj.y * -depth.y + depth.x;
       depth.x = 1.0/depth.x;
       depth.y = depth.z * depth.x;
       depth.x = depth.z * depth.x - dofDist.y;
       depth.x+= dofDist.x * -0.5;
       depth.x = max(depth.x, 0.0);
return depth.x;
}

float CL(in float3 c)
{
	return (c.r * 0.2126 + c.g * 0.7152 + c.b * 0.0722)*1.0;
}

float4 wpd0(in float2 cd, in float d)
{	
float4 tv;
       tv.xy = cd.xy*2.0-1.0;
       tv.y = -tv.y;
       tv.z = d;
       tv.w = 1.0;
float4 wp;
       wp.x = dot(tv, MatrixInverseVPRotation[0]);
       wp.y = dot(tv, MatrixInverseVPRotation[1]);
       wp.z = dot(tv, MatrixInverseVPRotation[2]);
       wp.w = dot(tv, MatrixInverseVPRotation[3]);
       wp.xyz/= wp.w;
       wp.xyz+= CameraPosition;
return wp;
}

float4 wpd1(float2 cd)
{
float4 tv; 
       tv.xy = cd.xy*2.0-1.0;   
       tv.y =-tv.y;   
       tv.z = tex2Dlod(SamplerDepth, float4(cd.xy,0,0)).x;
       tv.w = 1.0;
float4 wp;
	   wp.x = dot(tv,MatrixInverseVPRotation[0]);
	   wp.y = dot(tv,MatrixInverseVPRotation[1]);
	   wp.z = dot(tv,MatrixInverseVPRotation[2]);
	   wp.w = dot(tv,MatrixInverseVPRotation[3]);
	   wp.xyz/= wp.w;	   
return wp;
}

float2 wpd2(float3 cd)
{
float4 tv = float4(cd.xyz, 1.0);
float4 wp = 0.0;
       wp.x = dot(tv,MatrixVPRotation[0]);
       wp.y = dot(tv,MatrixVPRotation[1]);
       wp.z = dot(tv,MatrixVPRotation[2]);
       wp.w = dot(tv,MatrixVPRotation[3]);
       wp.xyz/= wp.w;
       wp.y = -wp.y;
       wp.xy = wp.xy*0.5+0.5;	  
return wp.xy;
}

float3 fs0(float2 cd)
{
  float3 wpos = wpd1(cd.xy);
  float2 fscreen = float2(ScreenSize.y,ScreenSize.y*ScreenSize.z);
  float3 y = wpd1(cd.xy+float2(fscreen.x, 0.0)) - wpos;
  float3 f = wpd1(cd.xy+float2(0.0, fscreen.y)) - wpos;
  float3 n = cross(f,y);		 
  return normalize(n);
}

float4 reflection(float3 n, float2 cd)
{
   float3 wpos = wpd1(cd.xy);
   float3 v = float3(0.353, 0.353, 1.0);
          n = (normalize(n.xyz*v)*0.98);
   float3 n0 = reflect(wpos.xyz, n.xyz);	 
   float3 n1 = ((1000.0/0.01)*n0)/1000.0;
   float3 r0 = (wpos+n1);
   float2 r1 = wpd2(r0.xyz);
   float4 r2 = tex2Dlod(SamplerColor, float4(r1.xy, 0.0, 6.0)); 
	      r2.w = r1.y<0.0||r1.y>1.0 ? 0.0:1.0;
   return r2;
}

float4 	WorldPos(in float2 coord)
{
   float  d0 = tex2D(SamplerDepth, coord.xy).x;
   float4 tvec; 
          tvec.xy = coord.xy*2.0-1.0;   
          tvec.y = -tvec.y;   
          tvec.z = d0;
          tvec.w = 1.0;
   float4 wpos;
          wpos.x = dot(tvec, MatrixInverseVPRotation[0]);
          wpos.y = dot(tvec, MatrixInverseVPRotation[1]);
          wpos.z = dot(tvec, MatrixInverseVPRotation[2]);
          wpos.w = dot(tvec, MatrixInverseVPRotation[3]);
          wpos.xyz/= wpos.w;
   return wpos;
}

float4 	GWP(in float2 c, in float d)
{
   float4 t; 
   float4 w;
   t.xy=c.xy*2.0-1.0;
   t.y=-t.y;
   t.z=d;
   t.w=1.0;
   w.x=dot(t, MatrixInverseVPRotation[0]);
   w.y=dot(t, MatrixInverseVPRotation[1]);
   w.z=dot(t, MatrixInverseVPRotation[2]);
   w.w=dot(t, MatrixInverseVPRotation[3]);
   w.xyz/=w.w;
   //w.xyz+=CameraPosition;
   return w;
}

float Coverage(in float v, in float d, in float c)
{
	c = clamp(c - (1.0 - v), 0.0, 1.0 - d)/(1.0 - d);
	c = max(0.0, c * 1.1 - 0.1);
	c = c = c * c * (3.0 - 2.0 * c);
	return c;
}

float3 ComputeRipple(float2 uv, float CurrentTime, float Weight)
{
    float4 rp = tex2Dlod(SamplerWrp, float4(uv, 0.0, 0.0))*0.5;
           rp.yz = rp.yz * 2.0-1.0;	
	   
float4  wx = WeatherAndTime;	   
float  wc;
float  wn;
if (wx.x==0,1) wc = 0.0;
if (wx.y==0,1) wn = 0.0;
if (wx.x==8)   wc = 2.0;
if (wx.x==16)  wc = 2.0;
if (wx.y==8)   wn = 2.0;
if (wx.y==16)  wn = 2.0;	  
      float rp0 = lerp(wc, wn, pow(wx.z, 0.5));
	   float DropFrac = frac(rp.w+CurrentTime);
	   float TimeFrac = DropFrac - 1.0 + rp.x;
	   float DropFactor = saturate(0.20 + Weight * 0.80 - DropFrac);
	   float PI = 3.14159265359;
	   float FF = DropFactor*rp.x * sin(clamp(TimeFrac * 12.0, 0.0, 5.0) * PI);
	   
	   float3 cpl = lerp(0.0, float3(rp.yz*FF*rp0, 1.0), rp);
	   return cpl;
}

float3 CR(float3 n, float3 uv)
{
float Tr = Timer.x * 14000.0;
float4 TimeMul = float4(0.6, 0.7, 0.8, 1.0); 
float4 TimeAdd = float4(0.22, 0.44, 0.66, 0.9);
float4 Times = (Tr * TimeMul + TimeAdd) * 2.4;
       Times = frac(Times);
float4 Weights = 1.0 - float4(0, 0.25, 0.5, 0.75);
       Weights = saturate(Weights * 4.0);
float3 Ripple1 = ComputeRipple(uv * 0.18 + float2(0.25, 0.0),  Times.x, Weights.x);
float3 Ripple2 = ComputeRipple(uv * 0.25 + float2(-0.55, 0.3), Times.y, Weights.y);
float3 Ripple3 = ComputeRipple(uv * 0.28 + float2(0.6, 0.85),  Times.z, Weights.z);
float3 Ripple4 = ComputeRipple(uv * 0.30 + float2(0.5, -0.75),  Times.w, Weights.w);
float3 Ripple5 = ComputeRipple(uv * 0.32 + float2(0.3, -0.42),  Times.w, Weights.w);
float3 Ripple6 = ComputeRipple(uv * 0.20 + float2(0.35, 0.1),  Times.x, Weights.x);
	n=normalize(float3(n.xy+Ripple1.xy,n.z));
	n=normalize(float3(n.xy+Ripple2.xy,n.z));
	n=normalize(float3(n.xy+Ripple3.xy,n.z));
	n=normalize(float3(n.xy+Ripple4.xy,n.z));	
	n=normalize(float3(n.xy+Ripple5.xy,n.z));
	n=normalize(float3(n.xy+Ripple6.xy,n.z));	
	return n;	
}

float3 ComputeRelief(float2 uv, float CurrentTime, float3 Weight)
{
    float tx = (Timer.x * 1000.0) * 1.05;
    float4 rf = tex2Dlod(SamplerWrl,  float4(uv.xy + float2(0.5, 0.5*tx), 0.0, 0.0));
		   rf.yz = rf.yz * 2.0-1.0;		   
       float RelfSt = step(0.2, rf.a);		   
	   float DropFrac = frac(rf.w+CurrentTime);
	   float3 DropFactor = saturate(0.2 + Weight * 0.8 - DropFrac);	
	   float3 FF = DropFactor * rf.x*RelfSt;
    return float3(rf.yz*FF, 1.0);
}

float3 PR(float3 n, float3 uv)
{
float4 t = 1.99;
float3 w = float3(1.2, 1.2, 1.2);
float tx = (Timer.x * 1000.0) * 1.05;	   
float3 Relief1 = ComputeRelief(uv * 0.05 + float2(0.55, 0.89),  t.x, w);
float3 Relief2 = ComputeRelief(uv * 0.25 + float2(0.22, 0.33)*tx,  t.x, w);	
	n=normalize(float3(n.xy+Relief1.xy,n.z)); 
	n=normalize(float3(n.xy+Relief2.xy,n.z));
    return n;
}

float4 PS_Rain(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR
{
   float4 r0 = tex2D(SamplerColor, IN.txcoord.xy);	
   float4 r1 = r0;	   
   float2 cd = IN.txcoord.xy;
   float d0 = tex2D(SamplerDepth, IN.txcoord.xy).x;
   float d1 = linearlizeDepth(tex2D(SamplerDepth, IN.txcoord.xy).x)*1.0;	   
   float4 tv0;
   float4 wpos;
   tv0.xy = IN.txcoord.xy*2.0-1.0;
   tv0.y =-tv0.y;
   tv0.z = d0;
   tv0.w = 1.0;
   wpos.x = dot(tv0, MatrixInverseVPRotation[0]);
   wpos.y = dot(tv0, MatrixInverseVPRotation[1]);
   wpos.z = dot(tv0, MatrixInverseVPRotation[2]);
   wpos.w = dot(tv0, MatrixInverseVPRotation[3]);
   wpos.xyz/= wpos.w;
   float4 npos;
   float4 n0 = tex2D(SamplerNormal, IN.txcoord.xy)*2.0-1.0;
   float4 tv1;
   tv1.xy = n0.xy;
   tv1.x = -tv1.x;
   tv1.z = n0.z;
   npos.x = dot(tv1.xyz, MatrixInverseView[0]);
   npos.y = dot(tv1.xyz, MatrixInverseView[1]);
   npos.z = dot(tv1.xyz, MatrixInverseView[2]);
   float3 n2 = normalize(npos.xyz);	  
          n2 = CR(n2.xyz, wpos+CameraPosition);  
          n2 = PR(n2.xyz, wpos+CameraPosition);  		  
    float3 vp = float3(0.0, 0.0, 1.03);
    float4 wc = wpd0(cd, d0);
	float rx = tex2Dlod(SamplerPuddle, float4(wc.xy*EPuddlesSize, 0.0, 0.0));	
float t = GameTime;		
   float x1 = smoothstep(0.0, 4.0, t);
   float x2 = smoothstep(4.0, 5.0, t);
   float x3 = smoothstep(5.0, 6.0, t);
   float x4 = smoothstep(6.0, 7.0, t);
   float xE = smoothstep(8.0, 11.0, t);
   float x5 = smoothstep(16.0, 17.0, t);
   float x6 = smoothstep(18.0, 19.0, t);
   float x7 = smoothstep(19.0, 20.0, t);
   float xG = smoothstep(20.0, 21.0, t);  
   float xZ = smoothstep(21.0, 22.0, t);
   float x8 = smoothstep(22.0, 23.0, t);
   float x9 = smoothstep(23.0, 24.0, t);     	
float rc;
float rn;
float4 Wx = WeatherAndTime;	
if (Wx.x==0,1) rc = 2.0;
if (Wx.y==0,1) rn = 2.0;
if (Wx.x==8)   rc = 0.2;
if (Wx.y==8)   rn = 0.2;
if (Wx.x==16)  rc = 0.2;
if (Wx.y==16)  rn = 0.2;	  
float wmix1 = lerp(rc, rn, pow(Wx.z, 8.5));
	float coverage = lerp(wmix1, EPuddlesAmount, EPuddlesalltime);
		  coverage = lerp(coverage, 0.87, 2.0);		  		  
	float density = 0.1 - 2.0 * 0.3;		  
	      rx = Coverage(coverage, density, rx);	
	float rh = smoothstep(0.999, 1.0, dot(-vp, -fs0(cd)));
	float4 rx2 = rx; 
	       rx2.a = min(1.0, rx2.a);  
	  float4 skyenv=tex2D(SamplerEnv, cd);		   
    float3 ssr = skyenv;	
	float4 rfl = reflection(n2.xyz, IN.txcoord.xy);		
           rfl = (rfl * 1.05); 
    float3 wp0 = wpd1(cd.xy);
    float3 p3 = float3(0.353, 0.353, 1.0);
           n2 = (normalize(n2.xyz*p3)*0.98);
    float3 nz = reflect(wp0.xyz, n2.xyz); 
    float3 rw = ((1000.0/0.01)*nz)/1000.0;	
    float3 ref11 = (wp0+rw);
    float2 rd = wpd2(ref11.xyz);		
	float  nf0 = saturate(8.0*(rd.y));
	       nf0 = pow(nf0, 1.5);
           ssr=lerp(ssr, rfl.xyz, rfl.w*nf0);
	float4 n1 = tex2D(SamplerNormal, IN.txcoord.xy);     
	float  rmix;		 
	       rmix=saturate(n1.z)*saturate(n1.z);
	       rmix*=rmix;					
		ssr.xyz=lerp(ssr, skyenv, rmix);
		ssr.xyz=lerp(ssr, r0*0.15, pow(rmix, 1.2));	
float wcr;
float wnr;
if (Wx.x==0,1) wcr = 0.0;
if (Wx.y==0,1) wnr = 0.0;
if (Wx.x==8)   wcr = 1.0;
if (Wx.x==16)  wcr = 1.0;
if (Wx.y==8)   wnr = 1.0;
if (Wx.y==16)  wnr = 1.0;	  
	float wmix = lerp(wcr, wnr, pow(Wx.z, 0.07));
	float4 nw = tex2D(SamplerNormal, IN.txcoord.xy).w;	  
	if (nw.w<1.0) nw = 0.0;
		  
	float3 n3 = CR(float3(0.0, 1.0, 1.0), wpos+CameraPosition);  		 
	float3 sv = normalize(float3(0.0, 0.0, 1.0));	 	
    float t1 = lerp(0.04, 0.04, x1);
          t1 = lerp(t1, 0.04, x2);
          t1 = lerp(t1, 0.09, x3);
          t1 = lerp(t1, 0.09, x4);
          t1 = lerp(t1, 0.09, xE);
          t1 = lerp(t1, 0.09, x5);
          t1 = lerp(t1, 0.09, x6);		 
          t1 = lerp(t1, 0.08, x7);
		  t1 = lerp(t1, 0.07, xG);
		  t1 = lerp(t1, 0.06, xZ);
          t1 = lerp(t1, 0.05, x8);  
          t1 = lerp(t1, 0.04, x9);	
          t1*= 1.1;		  
   float factor = t1 - dot(sv, n2);
         factor = pow(factor, 12.0);
   float fr = (factor*factor); 
         fr/= 4.5;	
	float n6 = saturate(n3);
	float lp = lerp(0.0, fr, n6);
	
	if(d1 < 3000)r0.xyz = lerp(r0, 0.75*ssr+lp, nw*rh*rx2*1.0);  
	float4 rp = float4(normalize(wpos.xyz), 1.0);
	float3 rpos = normalize(rp.xyz)*1.0;
	float3x3 vec = float3x3(1,0,0,0,cos(0.25),sin(0.25),0,-sin(0.25),cos(0.25));				   
		   rpos = mul(rpos, vec);	
	float2 f0=float2(acos(rpos.z),atan(rpos.x/rpos.y));		  		  

  return r0;
}



//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

technique PostProcess
{
   pass P0
   {
      VertexShader = compile vs_3_0 VS_PostProcess();
      PixelShader  = compile ps_3_0 PS_Rain();
   }
}


